/*
 * JGO2RDF creates a RDF representation of GAF2 files, which are automatically sourced from GO ftp site.
 * Copyright (C) 2012 Matthew M. Hindle & Artem Lysenko
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package uk.co.jgo2rdf.goa.goa2rdf;

import com.google.common.io.Files;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.tdb.TDB;
import com.hp.hpl.jena.tdb.TDBFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.log4j.Logger;
import uk.co.jgo2rdf.exception.AccessionNonConformentException;
import uk.co.jgo2rdf.goa.goa2rdf.deligates.GOARDFizer;
import uk.co.jgo2rdf.goa.model.GOAEntry;
import uk.co.jgo2rdf.goa.model.NoIEAFilter;
import uk.co.jgo2rdf.goa.parser.GOAIndexer;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * @author matthew hindle
 *         Date: 13/02/12
 *         Time: 18:17
 */
public class ParseGOAFiles {

    private static final Logger log = Logger.getLogger(ParseGOAFiles.class);

    /**
     * @param jenaModel the model to create the RDF in
     * @param goEntry   the GOA entry to convert into RDF
     * @param url       the URL which contains the GAF2 file
     * @throws Exception
     */
    public static void parseGOAFromIndex(Model jenaModel, GOAEntry goEntry, URL url) throws Exception {
        GOARDFizer rdfizer = DelegateFactory.getDelegates().get(new File(url.getFile()).getName());
        if (rdfizer != null) {
            rdfizer.rdfizeGOA(jenaModel, goEntry, url.toString());
        } else {
            System.err.println(new File(url.getFile()).getName() + " does not have a delegate that can process it");
        }

    }

    public static void main(String[] args) throws Exception {

        File tbdDir = Files.createTempDir();
        tbdDir.deleteOnExit();

        File rdfOut = new File("rdfizedGAF2Files.rdf.gz");

        if (args.length > 0) {  //position 0 is the rdf file which will be created
            rdfOut = new File(args[0]);
        }

        if (args.length > 1) { //if you want the TDB rdf database created to be perminant specify here
            tbdDir = new File(args[1]);
        }

        String[] urls = getDefaultURLs();

        if (args.length > 2) { //if you want to use a subset of the GAF2 files supported
            urls = args[2].split(",");
        }

        TDB.init();
        Model jenaModel = TDBFactory.createModel(tbdDir.getAbsolutePath());

        for (String url : urls) {
            try {
                Set<String> tairIds = createRDFromFile(jenaModel, new URL(url));
                TDB.sync(jenaModel);
                log.info("Parsed annotation for " + tairIds.size() + " gene/protein entities from " + url);
            } catch (Exception e) {
                log.error(e);
                e.printStackTrace();
            }
        }

        //       URL url = new URL("file:////home/mhindle/Gp2Uniprot/gp2protein.tair.gz");
        //       URLConnection connection = url.openConnection();
        //       connection.setConnectTimeout(1000 * 60);

//        ParseGP2UniprotFile.parseIntoModel(jenaModel,
        //               new GZIPInputStream(connection.getInputStream()), Arrays.asList(new String[]{"XP_541092", "XP_540837"}), null);


        OutputStream stream = new GZIPOutputStream(new BufferedOutputStream(
                new FileOutputStream(rdfOut)));
        try {
            jenaModel.write(stream);
        } finally {
            stream.flush();
            stream.close();
        }
        log.info("Wrote RDF output to " + rdfOut);
        jenaModel.close();
    }

    private static String[] getDefaultURLs() {
        String ftpFolder = "ftp://ftp.geneontology.org/pub/go/gene-associations/";
        String[] urls = new String[]{
                "gene_association.goa_chicken.gz",
                "gene_association.goa_cow.gz",
                "gene_association.goa_dog.gz",
                "gene_association.goa_human.gz",
                "gene_association.goa_pig.gz",

                "gene_association.goa_uniprot_noiea.gz",
                "gene_association.tair.gz",
                "gene_association.gramene_oryza.gz",

                "gene_association.zfin.gz",
                "gene_association.aspgd.gz",
                "gene_association.cgd.gz",
                "gene_association.dictyBase.gz",
                "gene_association.fb.gz",
                "gene_association.GeneDB_Lmajor.gz",
                "gene_association.GeneDB_Pfalciparum.gz",
                "gene_association.GeneDB_Tbrucei.gz",
                "gene_association.GeneDB_tsetse.gz",
                "gene_association.mgi.gz",
                "gene_association.PAMGO_Atumefaciens.gz",

                "gene_association.PAMGO_Ddadantii.gz",
                "gene_association.PAMGO_Mgrisea.gz",
                "gene_association.PAMGO_Oomycetes.gz",

                "gene_association.sgn.gz",
                "gene_association.rgd.gz",
                "gene_association.sgd.gz",
                "gene_association.wb.gz",
                "gene_association.jcvi.gz"

        };

        for (int i = 0; i < urls.length; i++) {
            urls[i] = ftpFolder + urls[i];
        }
        return urls;
    }

    /**
     * @param jenaModel     the model to create the RDF in
     * @param indexLocation a pre-indexed GAF2 file
     * @param url           the URL which contains the GAF2 file
     * @return the gene/protein ids for which annotation was extracted
     * @throws Exception
     */
    public static Set<String> createRDFromIndex(Model jenaModel, String indexLocation, URL url) throws Exception {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        GOAIndexer index = new GOAIndexer(indexLocation, df);

        Set<String> ids = new HashSet<String>();

        Set<GOAEntry> entries = index.getAllEntries(new NoIEAFilter());
        for (GOAEntry goEntry : entries) {
            try {
                parseGOAFromIndex(jenaModel, goEntry, url);
                ids.add(goEntry.getDBObject_ID());
            } catch (AccessionNonConformentException e) {
                log.error(e);
                continue;
            }
        }
        return ids;
    }

    /**
     * @param jenaModel the model to create the RDF in
     * @param url       the URL which contains the GAF2 file
     * @return the gene/protein ids for which annotation was extracted
     * @throws Exception
     */
    public static Set<String> createRDFromFile(Model jenaModel, URL url) throws Exception {
        Set<String> ids = new HashSet<String>();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");

        File myTempDir = Files.createTempDir();
        myTempDir.deleteOnExit();

        if (url.getProtocol().equalsIgnoreCase("ftp")) {
            log.info("Fetch " + url.getFile() + " from " + url.getHost());

            FTPClient ftp = new FTPClient();
            try {
                ftp.connect(url.getHost());
                ftp.login("anonymous", "anonymous");
                ftp.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
                ftp.setFileType(FTP.BINARY_FILE_TYPE);

                GOAIndexer index = new GOAIndexer(
                        new GZIPInputStream(ftp.retrieveFileStream(url.getFile())),
                        df, Charset.defaultCharset(), myTempDir.getAbsolutePath());

                Set<GOAEntry> entries = index.getAllEntries(new NoIEAFilter());
                for (GOAEntry goEntry : entries) {
                    try {
                        parseGOAFromIndex(jenaModel, goEntry, url);
                        ids.add(goEntry.getDBObject_ID());
                    } catch (AccessionNonConformentException e) {
                        log.error(e);
                        continue;
                    }
                }
            } finally {
                ftp.disconnect();
                myTempDir.delete();
            }
        } else {
            URLConnection connection = url.openConnection();
            connection.setConnectTimeout(1000 * 60);
            try {
                GOAIndexer index = new GOAIndexer(
                        new GZIPInputStream(connection.getInputStream()), df, Charset.defaultCharset(), myTempDir.getAbsolutePath());
                Set<GOAEntry> entries = index.getAllEntries(new NoIEAFilter());
                for (GOAEntry goEntry : entries) {
                    try {
                        parseGOAFromIndex(jenaModel, goEntry, url);
                        ids.add(goEntry.getDBObject_ID());
                    } catch (AccessionNonConformentException e) {
                        log.error(e);
                        continue;
                    }
                }
            } finally {
                myTempDir.delete();
            }
        }
        return ids;
    }
}


